import {
  applyDecorators,
  createParamDecorator,
  ExecutionContext,
  UseGuards,
  SetMetadata,
} from '@nestjs/common';
import { dtoErrorType } from '../services/validation.service';
import { Request } from 'express';
import { Types } from 'mongoose';
import { CheckPermissionGuard } from '../guard/check-permission.guard';
import { UserRole } from '@/user/schemas/user.schema';
import type { Actions } from '@/casl/casl-ability.factory';

export interface JwtUser {
  _id: string | Types.ObjectId;
  id: string;
  username: string;
  role: UserRole;
}

declare module 'express' {
  interface Request {
    user?: JwtUser;
  }
}

export const User = createParamDecorator(
  (data: unknown, ctx: ExecutionContext): JwtUser => {
    const request = ctx.switchToHttp().getRequest<Request>();
    return request.user!;
  },
);
export const IS_CHECK_PERMISSION_KEY = 'is_check_permission';

interface IOptions {
  action?: Actions; // 自定义的操作类型，publish (默认是根据请求方法来判断，其他特殊的需要明示)
  key?: string; // 查找记录时候的 key，默认为id。channel 使用
  // 查找记录时候 value 的来源默认是 request.params
  value?: { type: 'params' | 'body' | 'query'; valueKey: string };
}

export interface CheckPermissionMeta {
  modelName: string | { casl: string; mongoose: string };
  errorType: dtoErrorType;
  options?: IOptions;
}
/**
 *
 * @param modelName 表名称/users/works | { casl: casl权限验证中定义的subject; mongoose: 数据表中定义的modelname名称 }。
 * channel是work表中的属性，但是casl中定义的subject是channel
 * @param errorType 无权限的报错提示信息
 * @param options
 * @returns
 */
export const checkPermission = (
  modelName: string | { casl: string; mongoose: string },
  errorType: dtoErrorType,
  options?: IOptions,
) => {
  const meta: CheckPermissionMeta = { modelName, errorType, options };
  return applyDecorators(
    SetMetadata(IS_CHECK_PERMISSION_KEY, meta),
    UseGuards(CheckPermissionGuard),
  );
};
